package com.xiaoluyy.demo.common;


import com.xiaoluyy.common.log.LogFactory;
import com.xiaoluyy.common.log.ILog;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.FatalBeanException;
import org.springframework.util.Assert;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.util.Date;


public class CommonBeanUtils extends BeanUtils{

    private static final ILog LOGGER = LogFactory.getLog(CommonBeanUtils.class);
    
    public static void normallyCopyBean(Object dest,Object original)
    {
    // 这里一定要注册默认值，使用null也可以
//        BigDecimalConverter bd = new BigDecimalConverter(new BigDecimal("0"));
//        DateConverter dc = new DateConverter();
//        DateConvert dc2 = new DateConvert();
//        ConvertUtils.register(bd, java.math.BigDecimal.class);
//        ConvertUtils.deregister(java.util.Date.class);
//        ConvertUtils.register(dc2, java.util.Date.class);
//        ConvertUtils.register(dc2, java.lang.String.class);
        try {
            //BeanUtils.copyProperties(original,dest );
            copyProperties(original,dest);
        } catch (Exception e) {
            LOGGER.error(
                     "CommonBeanUtils normallyCopyBean copy properties from original bean to aggregated bean Exception,", e);
        }
    }

    public static void copyProperties(Object source, Object target) throws BeansException {
           Assert.notNull(source, "Source must not be null");
          Assert.notNull(target, "Target must not be null");
            Class<?> actualEditable = target.getClass();
          PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);
            for (PropertyDescriptor targetPd : targetPds) {
                  if (targetPd.getWriteMethod() != null) {
                 PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());
                     if (sourcePd != null && sourcePd.getReadMethod() != null) {
                             try {
                                  Method readMethod = sourcePd.getReadMethod();
                                   if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
                                          readMethod.setAccessible(true);
                                        }
                                   Object value = readMethod.invoke(source);
                                   // 这里判断以下value是否为空 当然这里也能进行一些特殊要求的处理 例如绑定时格式转换等等
                                  if (value != null ) {
                                      if (java.util.Date.class.isAssignableFrom(readMethod.getReturnType()))
                                      {
                                          Method writeMethod = targetPd.getWriteMethod();
                                          if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
                                              writeMethod.setAccessible(true);
                                          }

                                          if(writeMethod.getParameterTypes()[0].isAssignableFrom(java.lang.Long.class) || writeMethod.getParameterTypes()[0].isAssignableFrom(long.class) )
                                          {
                                              writeMethod.invoke(target, ((Date)value).getTime());
                                          }
                                      }else if (java.math.BigDecimal.class.isAssignableFrom(readMethod.getReturnType()))
                                      {
                                          Method writeMethod = targetPd.getWriteMethod();
                                          if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
                                              writeMethod.setAccessible(true);
                                          }
                                          if(writeMethod.getParameterTypes()[0].isAssignableFrom(java.lang.Double.class) || writeMethod.getParameterTypes()[0].isAssignableFrom(double.class))
                                          {
                                              writeMethod.invoke(target, ((BigDecimal)value).doubleValue());
                                          }else if(writeMethod.getParameterTypes()[0].isAssignableFrom(java.lang.Float.class) || writeMethod.getParameterTypes()[0].isAssignableFrom(float.class))
                                          {
                                              writeMethod.invoke(target, ((BigDecimal)value).floatValue());
                                          }else if(writeMethod.getParameterTypes()[0].isAssignableFrom(java.lang.Integer.class) || writeMethod.getParameterTypes()[0].isAssignableFrom(int.class))
                                          {
                                              writeMethod.invoke(target, ((BigDecimal)value).intValue());
                                          } else if(writeMethod.getParameterTypes()[0].isAssignableFrom(java.lang.Long.class) || writeMethod.getParameterTypes()[0].isAssignableFrom(long.class))
                                          {
                                              writeMethod.invoke(target, ((BigDecimal)value).longValue());
                                          }
                                      }
                                      else{
                                          Method writeMethod = targetPd.getWriteMethod();
                                          if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
                                              writeMethod.setAccessible(true);
                                          }
                                          writeMethod.invoke(target, value);
                                      }

                                      }
                                  } catch (Throwable ex) {
                                   throw new FatalBeanException("Could not copy properties from source to target", ex);
                               }
                           }
                     }
               }
          }

}
